﻿using System.Reflection;

namespace Leo.Common
{
    public class ObjectToDictionaryConverter
    {
        public ObjectToDictionaryConverter(object instance)
        {
            this.instance = instance;
        }

        public IDictionary<string, object> ToDictionary(IDictionary<string, object> dictionary)
        {
            if (this.instance == null)
            {
                return dictionary;
            }
            IDictionary<string, object> dictionary2 = this.instance as IDictionary<string, object>;
            if (dictionary2 != null)
            {
                ObjectToDictionaryConverter.Copy(dictionary2, dictionary);
                return dictionary;
            }
            if (dictionary == null)
            {
                dictionary = new Dictionary<string, object>();
            }
            foreach (PropertyInfo property in this.instance.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public))
            {
                ObjectToDictionaryEntry objectToDictionaryEntry = new ObjectToDictionaryEntry(this.instance)
                {
                    Key = this.GetKeyName(property),
                    Property = property
                };
                this.OnBeforeEntryInsert(objectToDictionaryEntry);
                dictionary.Add(objectToDictionaryEntry.Key, objectToDictionaryEntry.Value);
                this.OnAfterEntryInsert(objectToDictionaryEntry, dictionary);
            }
            return dictionary;
        }

        private static void Copy(IDictionary<string, object> source, IDictionary<string, object> destination)
        {
            foreach (KeyValuePair<string, object> item in source)
            {
                destination.Add(item);
            }
        }

        private string GetKeyName(PropertyInfo property)
        {
            DictionaryKeyAttribute customAttribute = property.GetCustomAttribute<DictionaryKeyAttribute>();
            return ((customAttribute != null) ? customAttribute.Key : null) ?? property.Name;
        }

        private void OnAfterEntryInsert(ObjectToDictionaryEntry entry, IDictionary<string, object> dictionary)
        {
            try
            {
                Action<ObjectToDictionaryEntry, IDictionary<string, object>> afterEntryInsert = this.AfterEntryInsert;
                if (afterEntryInsert != null)
                {
                    afterEntryInsert(entry, dictionary);
                }
            }
            catch
            {
            }
        }

        private void OnBeforeEntryInsert(ObjectToDictionaryEntry entry)
        {
            try
            {
                Action<ObjectToDictionaryEntry> beforeEntryInsert = this.BeforeEntryInsert;
                if (beforeEntryInsert != null)
                {
                    beforeEntryInsert(entry);
                }
            }
            catch
            {
            }
        }

        public event Action<ObjectToDictionaryEntry> BeforeEntryInsert;

        public event Action<ObjectToDictionaryEntry, IDictionary<string, object>> AfterEntryInsert;

        private readonly object instance;
    }
}
